package cn.chenxinjie.hrm.controller;

import cn.chenxinjie.hrm.config.HighlightResultMapper;
import cn.chenxinjie.hrm.doc.CourseDoc;
import cn.chenxinjie.hrm.query.CourseDocQuery;
import cn.chenxinjie.hrm.repository.CourseDocRepository;
import cn.chenxinjie.hrm.util.AjaxResult;
import cn.chenxinjie.hrm.page.PageList;
import cn.chenxinjie.hrm.vo.AggVo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 陈鑫杰
 * @date 2022/3/15 17:26
 */
@RestController
@RequestMapping("/courseDoc")
public class CourseDocController {

    @Autowired // 可以使用这个对象但这里不使用
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
    private CourseDocRepository courseDocRepository;
    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @PostMapping
    @PreAuthorize("hasAuthority('courseDoc:add')")
    public AjaxResult addCourseDoc(@RequestBody List<CourseDoc> list){
        /*list.stream().forEach(e -> {
            courseDocRepository.save(e);
        });*/
        courseDocRepository.saveAll(list);
        return AjaxResult.me();
    }

    @PostMapping("/remove")
    @PreAuthorize("hasAuthority('courseDoc:delete')")
    public AjaxResult removeCourseDoc(@RequestBody List<Long> ids){
        ids.stream().forEach(e -> {
            courseDocRepository.deleteById(e);
        });
        return AjaxResult.me();
    }

    @PostMapping("/queryCourses")
    public AjaxResult queryCourses(@RequestBody CourseDocQuery query){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        // 分页参数封装
        builder.withPageable(PageRequest.of((query.getPage() - 1),query.getRows()));
        // 排序参数封装
        String sortField = query.getSortField();
        // 校验排序是否传入字段如果没有传入字段就给默认字段:价格
        sortField = StringUtils.isEmpty(sortField) ? "price" : sortField;
        // 判断排序方式 不是降序就是升序
        String sortType = query.getSortType();
        SortOrder sortOrder = "desc".equals(sortType) ? SortOrder.DESC : SortOrder.ASC;
        FieldSortBuilder sortBuilder = new FieldSortBuilder(sortField).order(sortOrder);
        builder.withSort(sortBuilder);
        // 关键字查询
        String keyword = query.getKeyword();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(keyword)) {
            boolQuery.must(QueryBuilders.multiMatchQuery(keyword, "name","courseTypeName","gradeName"));
        }
        String courseTypeName = query.getCourseTypeName();
        if (!StringUtils.isEmpty(courseTypeName)) {
            boolQuery.must(QueryBuilders.matchQuery("courseTypeName",courseTypeName));
        }
        // 过滤参数封装
        Float min = query.getPriceMin();
        if (min != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(min));
        }
        Float max = query.getPriceMax();
        if (max != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(max));
        }
        builder.withQuery(boolQuery);
        // 高亮的实现,在返回结果之前将结果拦截然后在搜索的关键字前后加上标签
        // 设置高亮显示
        HighlightBuilder.Field field = new HighlightBuilder.Field("name").preTags("<font style='color:red'><b>").postTags("</b></font>");
        builder.withHighlightFields(field);
        // 聚合查询
        builder.addAggregation(AggregationBuilders.terms("tenantNameAgg").field("tenantName").order(Terms.Order.count(false)).size(20));
        builder.addAggregation(AggregationBuilders.terms("couseTypeAgg").field("courseTypeName").order(Terms.Order.count(false)).size(20));
        // ElasticsearchRepository不支持高亮,但是elasticsearchTemplate支持高亮
        //Page<CourseDoc> page = courseDocRepository.search(nativeSearchQuery);
        NativeSearchQuery nativeSearchQuery = builder.build();
        AggregatedPage<CourseDoc> page = elasticsearchTemplate.queryForPage(nativeSearchQuery, CourseDoc.class, highlightResultMapper);
        StringTerms tenantNameAgg = (StringTerms) page.getAggregation("tenantNameAgg");
        List<StringTerms.Bucket> tenantNameAggBuckets = tenantNameAgg.getBuckets();
        List<AggVo> tenantAgg = new ArrayList<>();
        tenantNameAggBuckets.stream().forEach(bucket -> {
            AggVo aggVo = new AggVo();
            aggVo.setName(bucket.getKeyAsString());
            aggVo.setCount(bucket.getDocCount());
            tenantAgg.add(aggVo);
        });
        StringTerms couseTypeAgg = (StringTerms) page.getAggregation("couseTypeAgg");
        List<StringTerms.Bucket> couseTypeAggBuckets = couseTypeAgg.getBuckets();
        List<AggVo> typeAgg = new ArrayList<>();
        couseTypeAggBuckets.stream().forEach(bucket -> {
            AggVo aggVo = new AggVo();
            aggVo.setName(bucket.getKeyAsString());
            aggVo.setCount(bucket.getDocCount());
            typeAgg.add(aggVo);
        });
        Map<String,List<AggVo>> map = new HashMap<>();
        map.put("tenantAgg",tenantAgg);
        map.put("typeAgg",typeAgg);
        return AjaxResult.me().setResultObj(new PageList<>(page.getTotalElements(), page.getContent(),map));
    }
}
